
package com.shop.cloud.mall.admin.controller;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.shop.cloud.common.core.constant.CommonConstants;
import com.shop.cloud.common.core.constant.SecurityConstants;
import com.shop.cloud.common.core.util.LocalDateTimeUtils;
import com.shop.cloud.common.core.util.R;
import com.shop.cloud.common.data.tenant.TenantContextHolder;
import com.shop.cloud.common.log.annotation.SysLog;
import com.shop.cloud.mall.admin.service.ShopDepositConfigService;
import com.shop.cloud.mall.admin.service.ShopInfoService;
import com.shop.cloud.mall.common.config.MallConfigProperties;
import com.shop.cloud.mall.common.constant.MallConstants;
import com.shop.cloud.mall.common.constant.MallReturnCode;
import com.shop.cloud.mall.common.entity.ShopDeposit;
import com.shop.cloud.mall.admin.service.ShopDepositService;
import com.shop.cloud.mall.common.entity.ShopDepositConfig;
import com.shop.cloud.mall.common.entity.ShopInfo;
import com.shop.cloud.pay.common.dto.AliBaseRequest;
import com.shop.cloud.pay.common.entity.PayConfig;
import com.shop.cloud.pay.common.feign.FeignPayService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

/**
 * 店铺保证金
 *
 * @author
 * @date 2023-11-28 16:00:01
 */
@Slf4j
@RestController
@AllArgsConstructor
@RequestMapping("/shopdeposit")
@Tag(description = "shopdeposit", name = "店铺保证金管理")
public class ShopDepositController {

    private final ShopDepositService shopDepositService;
    private final ShopDepositConfigService shopDepositConfigService;
    private final FeignPayService feignPayService;
    private final MallConfigProperties mallConfigProperties;
    private final ShopInfoService shopInfoService;

    /**
     * 店铺保证金分页列表
     * @param page 分页对象
     * @param shopDeposit 店铺保证金
     * @return
     */
    @Operation(summary = "店铺保证金分页列表")
    @GetMapping("/page")
    @PreAuthorize("@ato.hasAuthority('mall:shopdeposit:index')")
    public R getPage(Page page, ShopDeposit shopDeposit) {
        return R.ok(shopDepositService.page(page, Wrappers.query(shopDeposit)));
    }

    /**
     * 店铺保证金查询
     * @param id
     * @return R
     */
    @Operation(summary = "店铺保证金查询")
    @GetMapping("/{id}")
    @PreAuthorize("@ato.hasAuthority('mall:shopdeposit:get')")
    public R getById(@PathVariable("id") String id) {
        return R.ok(shopDepositService.getById(id));
    }

    /**
     * 店铺保证金提现申请
     * @param shopDeposit 店铺保证金
     * @return R
     */
    @Operation(summary = "店铺保证金提现申请")
    @SysLog("店铺保证金提现申请")
    @PutMapping("/status/apply")
    @PreAuthorize("@ato.hasAuthority('mall:shopdeposit:withdraw:apply')")
    public R updateStatusApply(@RequestBody ShopDeposit shopDeposit) {
        shopDeposit.setStatus(MallConstants.SHOP_DEPOSIT_STATUS_2);
        shopDeposit.setIsPay(null);
        //下线店铺
        ShopInfo shopInfo = new ShopInfo();
        shopInfo.setId(shopDeposit.getShopId());
        shopInfo.setEnable(CommonConstants.NO);
        shopInfoService.updateById(shopInfo);
        return R.ok(shopDepositService.updateById(shopDeposit));
    }

    /**
     * 店铺保证金提现审核
     * @param shopDeposit 店铺保证金
     * @return R
     */
    @Operation(summary = "店铺保证金提现审核")
    @SysLog("店铺保证金提现审核")
    @PutMapping("/status/examine")
    @PreAuthorize("@ato.hasAuthority('mall:shopdeposit:withdraw:examine')")
    public R updateStatusExamine(@RequestBody ShopDeposit shopDeposit) {
        shopDeposit.setIsPay(null);
        if(MallConstants.SHOP_DEPOSIT_STATUS_3.equals(shopDeposit.getStatus())){
            shopDeposit.setIsPay(CommonConstants.NO);
        }
        return R.ok(shopDepositService.updateById(shopDeposit));
    }

    /**
     * 统一下单，支付保证金
     * @param shopDeposit
     * @return
     */
    @Operation(summary = "统一下单，支付保证金")
    @SysLog("统一下单，支付保证金")
    @PostMapping("/unified")
    public R unifiedShopDeposit(HttpServletRequest request, @RequestBody ShopDeposit shopDeposit) {
        String paymentType = shopDeposit.getPaymentType();
        if(StrUtil.isBlank(paymentType)){
            return R.failed(MallReturnCode.ERR_70002.getCode(), MallReturnCode.ERR_70002.getMsg());
        }
        ShopDepositConfig shopDepositConfig = shopDepositConfigService.getOne(Wrappers.emptyWrapper());
        if(shopDepositConfig == null || CommonConstants.NO.equals(shopDepositConfig.getEnable())){
            return R.failed("店铺保证金功能未开启");
        }
        ShopDeposit shopDeposit2 = shopDepositService.getById(shopDeposit.getShopId());
        if(shopDeposit2 != null && MallConstants.SHOP_DEPOSIT_STATUS_1.equals(shopDeposit2.getStatus())){
            return R.failed("该店铺已缴保证金");
        }
        shopDeposit.setAmount(shopDepositConfig.getAmount());
        shopDeposit.setIsPay(CommonConstants.NO);
        shopDeposit.setTenantId(TenantContextHolder.getTenantId());
        shopDeposit.setTradeNo(IdUtil.getSnowflake(0,0).nextIdStr());
        shopDeposit.setStatus(null);
        shopDepositService.saveOrUpdate(shopDeposit);
        //获取支付配置
        R<PayConfig> r = feignPayService.getPayConfigByType(paymentType, SecurityConstants.FROM_IN);
        if(!r.isOk()){
            return R.failed(r.getMsg());
        }
        PayConfig payConfig = r.getData();
        if(payConfig == null){
            return R.failed("支付未配置");
        }
        ShopInfo shopInfo = shopInfoService.getById(shopDeposit.getShopId());
        String body = "支付店铺保证金：" + shopInfo.getName();
        body = body.length() > 40 ? body.substring(0,39) : body;
        //微信支付
        if(MallConstants.ORDER_PAYMENT_TYPE_1.equals(paymentType)){
            WxPayUnifiedOrderRequest wxPayUnifiedOrderRequest = new WxPayUnifiedOrderRequest();
            wxPayUnifiedOrderRequest.setSubMchId(payConfig.getSpecialMchId());
            wxPayUnifiedOrderRequest.setBody(body);
            wxPayUnifiedOrderRequest.setOutTradeNo(shopDeposit.getTradeNo());
            wxPayUnifiedOrderRequest.setTotalFee(shopDeposit.getAmount().multiply(new BigDecimal(100)).intValue());
            wxPayUnifiedOrderRequest.setTradeType("NATIVE");//扫码支付
            wxPayUnifiedOrderRequest.setNotifyUrl(mallConfigProperties.getNotifyHost()+MallConstants.SERVER_ROUTE_NAME_MALL+ "/shopdeposit/notify-wx/"+shopDeposit.getTenantId());
            wxPayUnifiedOrderRequest.setSpbillCreateIp(request.getRemoteAddr());
            return feignPayService.unifiedOrderWx(wxPayUnifiedOrderRequest, SecurityConstants.FROM_IN);
        }else if(MallConstants.ORDER_PAYMENT_TYPE_2.equals(paymentType)){//支付宝支付
            Map<String, Object> params = new HashMap<>();
            params.put("tradeType","QRCODE");//扫码支付
            params.put("outTradeNo",shopDeposit.getTradeNo());
            params.put("totalAmount",shopDeposit.getAmount().toString());
            params.put("notifyUrl",mallConfigProperties.getNotifyHost()+MallConstants.SERVER_ROUTE_NAME_MALL + "/shopdeposit/notify-ali/" + shopDeposit.getTenantId());
            params.put("returnUrl",shopDeposit.getReturnUrl());
            params.put("subject",body);
            AliBaseRequest aliBaseRequest = new AliBaseRequest();
            aliBaseRequest.setAppAuthToken(payConfig.getSpecialMchId());
            aliBaseRequest.setParams(params);
            return feignPayService.unifiedOrderAli(aliBaseRequest, SecurityConstants.FROM_IN);
        }else{
            return R.failed("无此支付类型");
        }
    }

    /**
     * 支付回调（微信）
     * @param xmlData
     * @return
     * @throws WxPayException
     */
    @Operation(summary = "支付回调（微信）")
    @PostMapping("/notify-wx/{tenantId}")
    public String notifyOrderWx(@RequestBody String xmlData, @PathVariable("tenantId") String tenantId) {
        log.info("支付回调（微信）:"+xmlData);
        TenantContextHolder.setTenantId(tenantId);//设置租户ID
        R<WxPayOrderNotifyResult> r = feignPayService.notifyOrderWx(xmlData, SecurityConstants.FROM_IN);
        if(r.isOk()){
            WxPayOrderNotifyResult notifyResult = r.getData();
            ShopDeposit shopDeposit = shopDepositService.getOne(Wrappers.<ShopDeposit>lambdaQuery()
                    .eq(ShopDeposit::getTradeNo,notifyResult.getOutTradeNo()));
            if(shopDeposit != null){
                if(shopDeposit.getAmount().multiply(new BigDecimal(100)).intValue() == notifyResult.getTotalFee()){
                    String timeEnd = notifyResult.getTimeEnd();
                    LocalDateTime paymentTime = LocalDateTimeUtils.parse(timeEnd);
                    shopDeposit.setPaymentTime(paymentTime);
                    shopDeposit.setTransactionId(notifyResult.getTransactionId());
                    shopDeposit.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_1);
                    shopDepositService.notifyShopDeposit(shopDeposit);
                    return WxPayNotifyResponse.success("成功");
                }else{
                    return WxPayNotifyResponse.fail("付款金额与订单金额不等");
                }
            }else{
                return WxPayNotifyResponse.fail("无此订单");
            }
        }else{
            return WxPayNotifyResponse.fail(r.getMsg());
        }
    }

    /**
     * 支付回调（支付宝）
     * @param request
     * @return
     * @throws
     */
    @Operation(summary = "支付回调（支付宝）")
    @ResponseBody
    @PostMapping("/notify-ali/{tenantId}")
    public String notifyOrderAli(HttpServletRequest request, @PathVariable("tenantId") String tenantId) {
        log.info("支付回调（支付宝）");
        Map<String, String> params = new HashMap<>();
        Map requestParams = request.getParameterMap();
        for (Iterator iter = requestParams.keySet().iterator(); iter.hasNext(); ) {
            String name = (String) iter.next();
            String[] values = (String[]) requestParams.get(name);
            String valueStr = "";
            for (int i = 0; i < values.length; i++) {
                valueStr = (i == values.length - 1) ? valueStr + values[i] : valueStr + values[i] + ",";
            }
            params.put(name, valueStr);
        }
        String appId = request.getParameter("app_id");
        if(StrUtil.isBlank(appId)){
            return "appId不能为空";
        }
        TenantContextHolder.setTenantId(tenantId);//设置租户ID
        ShopDeposit shopDeposit = shopDepositService.getOne(Wrappers.<ShopDeposit>lambdaQuery()
                .eq(ShopDeposit::getTradeNo,request.getParameter("out_trade_no")));
        if(shopDeposit == null){
            log.error("无此订单out_trade_no："+request.getParameter("out_trade_no"));
            return "无此订单";
        }
        if(shopDeposit.getAmount().compareTo(new BigDecimal(request.getParameter("total_amount"))) == 0){
            LocalDateTime paymentTime = LocalDateTimeUtils.parse(request.getParameter("gmt_payment"));
            shopDeposit.setPaymentTime(paymentTime);
            shopDeposit.setTransactionId(request.getParameter("trade_no"));
            shopDeposit.setPaymentType(MallConstants.ORDER_PAYMENT_TYPE_2);
            shopDepositService.notifyShopDeposit(shopDeposit);
            log.info("支付回调（支付宝）success");
            return "success";
        }else{
            log.error("付款金额与订单金额不等out_trade_no："+request.getParameter("out_trade_no"));
            return "付款金额与订单金额不等";
        }

    }
}
